<?php
/**
 * (ajax)
 */
namespace App\Admin\Ajax\Warehousing;

use App\Util\SerialNo;
use App\Models\Sys\Logs;
use App\Models\Basics\SysArea;
use App\Models\Inventory\InventoryCn;
use App\Models\Inventory\Record;
use App\Models\Inventory\Storage;
use App\Models\Purchase\PurchaseOrder;
use App\Models\Purchase\PurchaseOrderDetail;
use App\Models\Stocking\StockingApply;
use App\Models\Stocking\StockingApplyDetail;
use Encore\Admin\Facades\Admin;
use Illuminate\Support\Facades\DB;
class ReceiveAjax {

    /**
     * 获取公共站点ID
     * @return int
     */
    private function _getSysAreaPublicId(){
        return SysArea::getSysAreaIdByArea(); //PUBLIC站点
    }

    /**
     * 采购收货 -- 入库
     * 1.入库单
     * 2.更新PUBLIC在途、在库
     * 3.更新采购单已收货数量和状态
     * 4.更新备货单状态
     * @param $param
     * @return \Illuminate\Http\JsonResponse
     */
    public function purReceive($param){
        try{
            DB::beginTransaction();
            $basic = $param['basic'];
            $orderNo = $basic['order_no'];
            $detail = $param['detail'];
            $storageDetail = [];
            $logs = [];//采购单收货日志 [psku_code => storage_num]
            $storageAt = date('Y-m-d');
            $userId = Admin::user()->id;
            $areaPublicId = $this->_getSysAreaPublicId();
            $flag1 = false;
            foreach ($detail as $k => $v){
                //入库明细
                $storageDetail[$k]['order_no'] = $orderNo;
                $storageDetail[$k]['detail_id'] = $v['detail_id'];
                $storageDetail[$k]['psku_id'] = $v['psku_id'];
                $storageDetail[$k]['storage_num'] = $v['storage_num'];
                $storageDetail[$k]['supplier_price'] = $v['supplier_price'];
                $storageDetail[$k]['unit_price'] = $v['unit_price'];
                $storageDetail[$k]['unit_price_no_tax'] = $v['unit_price_no_tax'];
                $storageDetail[$k]['pack_price'] = $v['pack_price'];

                //更新public站点库存，并添加库存出入库记录日志
                $flag2 = $this->_purReceiveRewritePublic($userId,$areaPublicId,$v['psku_id'],$v['storage_num']);
                if(!$flag2){
                    $flag1 = false;
                    break;
                }

                //更新采购单据收货状态，更新备货单据收货状态
                $flag3 = $this->_purReceiveRewriteDetail($v['detail_id'],$v['storage_num']);
                if(!$flag3){
                    $flag1 = false;
                    break;
                }
                $flag1 = true;

                //日志数据
                $logs[$v['psku_code']] = $v['storage_num'];
            }
            if(!$flag1){
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }

            //更新采购单据收货状态，并记录采购日志
            $flag4 = $this->_purReceiveRewritePOAndLogs($orderNo,$logs);
            if(!$flag4){
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }

            //收货入库（国内库存）
            $storage = Storage::create([
                'storage_no' => SerialNo::getRsNo(),
                'storage_at' => $storageAt,
                'supplier_id' => $basic['supplier_id'],
                'cuser_id' => $userId
            ]);
            $storage->detail()->createMany($storageDetail);
            if($storage){
                //站点库存配额...
                //收货入库，触发站点在途分配逻辑(待实现)

                DB::commit();
                return response()->json(['status' => true,'message' => '操作成功！']);
            }else{
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }
        }catch (\Exception $e){
            DB::rollBack();
            report($e);
            return response()->json(['status' => false, 'message' => '系统异常！']);
        }
    }

    /**
     * *采购收货 -- 入库*
     * 公共库存数据回写
     * @param $userId
     * @param $areaId
     * @param $pSkuId
     * @param $storageNum
     * @return bool
     */
    private function _purReceiveRewritePublic($userId,$areaId,$pSkuId,$storageNum){
        DB::beginTransaction();
        $inventory = InventoryCn::query()
            ->where('area_id', $areaId)
            ->where('psku_id', $pSkuId)
            ->lockForUpdate()
            ->first();
        if(!$inventory){
            DB::rollBack();
            return false;
        }
        $inventory->transit -= min($inventory->transit,$storageNum);
        $inventory->instant += $storageNum;
        $flag1 = $inventory->save();
        if(!$flag1){
            DB::rollBack();
            return false;
        }

        //库存出入库记录
        $flag2 = Record::create([
            'record_no' => SerialNo::getRcNo(),
            'psku_id' => $pSkuId,
            'area_id' => $areaId,
            'action_type' => Record::ACTION_RECEIVE, //收货
            'record_type' => Record::TYPE_IN, //入库
            'num' => $storageNum,
            'user_id' => $userId,
        ]);
        if(!$flag2){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }

    /**
     * *采购收货 -- 入库*
     * 采购明细数据和备货数据回写
     * @param $detailId
     * @param $storageNum
     * @return bool
     */
    private function _purReceiveRewriteDetail($detailId,$storageNum){
        DB::beginTransaction();

        //更新采购单明细，收货状态
        $pod = PurchaseOrderDetail::query()->findOrFail($detailId);
        $pod->rgoods_num += $storageNum; //已收货数量
        if($pod->rgoods_num == 0){
            $pod->received_status = PurchaseOrderDetail::RECEIVED_NO; //未收货
        }elseif($pod->rgoods_num >= $pod->order_num){
            $pod->received_status = PurchaseOrderDetail::RECEIVED_ALL; //完全到货
        }else{
            $pod->received_status = PurchaseOrderDetail::RECEIVED_PART; //部分到货
        }
        $flag1 = $pod->save();
        if(!$flag1){
            DB::rollBack();
            return false;
        }

        //更新备货，收货状态
        $flag2 = false;
        foreach ($pod->stocking_detail as $item){
            $flag3 = $this->__purReceiveRewriteStocking($item->apply_detail_id,$pod->received_status);
            if(!$flag3){
                $flag2 = false;
                break;
            }
            $flag2 = true;
        }
        if(!$flag2){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }

    /**
     * *采购收货 -- 出，入库*
     * 采购单回写并记录日志
     * @param $orderNo
     * @param $logs
     * @return bool
     */
    private function _purReceiveRewritePOAndLogs($orderNo,$logs){
        DB::beginTransaction();
        $detailReStatus = PurchaseOrderDetail::query()->where('purchase_no',$orderNo)->pluck('received_status')->toArray();
        $reStatus = StockingApplyDetail::extractStatus($detailReStatus);

        //采购单
        $po = PurchaseOrder::query()->where('purchase_no',$orderNo)->first();
        $po->received_status = $reStatus; //收货状态
        $flag = $po->save();
        if(!$flag){
            DB::rollBack();
            return false;
        }

        //日志
        $flag1 = $this->__purReceiveRewriteLogs($po->id,$logs);
        if(!$flag1){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }

    /**
     * *采购收货 -- 出，入库*
     * 备货数据回写
     * @param $applyDetailId
     * @param $receivedStatus
     * @return bool
     */
    private function __purReceiveRewriteStocking($applyDetailId,$receivedStatus){
        DB::beginTransaction();

        //备货单明细
        $sad = StockingApplyDetail::query()->find($applyDetailId);
        $sad->re_status = $receivedStatus;
        $flag1 = $sad->save();
        if(!$flag1){
            DB::rollBack();
            return false;
        }

        //备货单
        $detailReStatus = StockingApplyDetail::query()->where('stocking_no',$sad->stocking_no)->pluck('re_status')->toArray();
        $reStatus = StockingApplyDetail::extractStatus($detailReStatus);
        $sa = StockingApply::query()->where('stocking_no',$sad->stocking_no)->first();
        $sa->re_status = $reStatus;
        $flag2 = $sa->save();
        if(!$flag2){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }

    /**
     * *采购收货 -- 入库*
     * 采购收货日志
     * @param $poId
     * @param $logs
     * @return bool
     */
    private function __purReceiveRewriteLogs($poId,$logs){
        $content = "采购单收货".PHP_EOL;
        foreach($logs as $k => $v){
            $content .= $k."收货数量".$v.PHP_EOL;
        }
        $flag = Logs::logs('purchase',$content,$poId);
        if(!$flag)return false;
        return true;
    }

    /**
     * 采购收货 -- 出库
     * 1.入库单
     * 2.更新PUBLIC在途、在库
     * 3.更新采购单已收货数量和状态
     * 4.更新备货单状态
     * @param $param
     * @return \Illuminate\Http\JsonResponse
     */
    public function purReceiveOut($param){
        try{
            $basic = $param['basic'];
            $orderNo = $basic['order_no'];
            $detail = $param['detail'];
            $storageDetail = [];
            $logs = [];//采购单收货日志 [psku_code => storage_num]
            DB::beginTransaction();
            $storageAt = date('Y-m-d');
            $userId = Admin::user()->id;
            $areaPublicId = $this->_getSysAreaPublicId(); //public站点
            $flag1 = false;
            foreach ($detail as $k => $v){
                //入库明细
                $storageDetail[$k]['order_no'] = $orderNo;
                $storageDetail[$k]['detail_id'] = $v['detail_id'];
                $storageDetail[$k]['psku_id'] = $v['psku_id'];
                $storageDetail[$k]['storage_num'] = -$v['storage_num'];
                $storageDetail[$k]['supplier_price'] = $v['supplier_price'];
                $storageDetail[$k]['unit_price'] = $v['unit_price'];
                $storageDetail[$k]['unit_price_no_tax'] = $v['unit_price_no_tax'];
                $storageDetail[$k]['pack_price'] = $v['pack_price'];

                //更新public站点库存，并添加库存出入库记录日志
                $flag2 = $this->_purReceiveOutRewritePublic($userId,$areaPublicId,$v['psku_id'],$v['storage_num']);
                if(!$flag2){
                    $flag1 = false;
                    break;
                }
                //更新采购单据收货状态，更新备货单据收货状态
                $flag3 = $this->_purReceiveOutRewriteDetail($v['detail_id'],$v['storage_num']);
                if(!$flag3){
                    $flag1 = false;
                    break;
                }
                $flag1 = true;
                //日志数据
                $logs[$v['psku_code']] = -$v['storage_num'];
            }
            if(!$flag1){
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }
            //采购单状态回写并记录日志
            $flag4 = $this->_purReceiveRewritePOAndLogs($orderNo,$logs);
            if(!$flag4){
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }
            $storage = Storage::create([
                'storage_no' => SerialNo::getRsNo(),
                'storage_at' => $storageAt,
                'supplier_id' => $basic['supplier_id'],
                'cuser_id' => $userId
            ]);
            $storage->detail()->createMany($storageDetail);
            if($storage){
                DB::commit();
                return response()->json(['status' => true,'message' => '操作成功！']);
            }else{
                DB::rollBack();
                return response()->json(['status' => false, 'message' => '操作失败！']);
            }
        }catch (\Exception $e){
            DB::rollBack();
            report($e);
            return response()->json(['status' => false, 'message' => '系统异常！']);
        }
    }

    /**
     * *采购收货 -- 出库*
     * 公共库存数据回写
     * @param $userId
     * @param $areaId
     * @param $pSkuId
     * @param $storageNum
     * @return bool
     */
    private function _purReceiveOutRewritePublic($userId,$areaId,$pSkuId,$storageNum){
        DB::beginTransaction();
        $inventory = InventoryCn::query()
            ->where('area_id' , $areaId)
            ->where('psku_id' , $pSkuId)
            ->lockForUpdate()
            ->first();
        if(!$inventory){
            DB::rollBack();
            return false;
        }
        $inventory->transit += $storageNum;
        $inventory->instant -= min($inventory->instant,$storageNum);
        $flag1 = $inventory->save();
        if(!$flag1){
            DB::rollBack();
            return false;
        }

        //库存出入库记录
        $flag2 = Record::create([
            'record_no' => SerialNo::getRcNo(),
            'psku_id' => $pSkuId,
            'area_id' => $areaId,
            'action_type' => Record::ACTION_RECEIVE, //收货
            'record_type' => Record::TYPE_IN, //入库
            'num' => -$storageNum,
            'user_id' => $userId,
        ]);
        if(!$flag2){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }

    /**
     * *采购收货 -- 出库*
     * 采购明细数据和备货数据回写
     * @param $detailId
     * @param $storageNum
     * @return bool
     */
    private function _purReceiveOutRewriteDetail($detailId,$storageNum){
        DB::beginTransaction();

        //更新采购单明细，收货状态
        $pod = PurchaseOrderDetail::query()->findOrFail($detailId);
        if($pod->rgoods_num < $storageNum){
            DB::rollBack();
            return false;
        }
        $pod->rgoods_num -= $storageNum; //已收货数量
        if($pod->rgoods_num == 0){
            $pod->received_status = PurchaseOrderDetail::RECEIVED_NO; //未收货
        }elseif($pod->rgoods_num >= $pod->order_num){
            $pod->received_status = PurchaseOrderDetail::RECEIVED_ALL; //完全到货
        }else{
            $pod->received_status = PurchaseOrderDetail::RECEIVED_PART; //部分到货
        }
        $flag1 = $pod->save();
        if(!$flag1){
            DB::rollBack();
            return false;
        }

        //更新备货，收货状态
        $flag2 = false;
        foreach ($pod->stocking_detail as $item){
            $flag3 = $this->__purReceiveRewriteStocking($item->apply_detail_id,$pod->received_status);
            if(!$flag3){
                $flag2 = false;
                break;
            }
            $flag2 = true;
        }
        if(!$flag2){
            DB::rollBack();
            return false;
        }
        //DB::commit();
        return true;
    }
}
